package com.net.model.model;

import androidx.lifecycle.MutableLiveData;

import com.drug.lib.util.DLog;
import com.net.model.base.BaseHttpSubscriber;
import com.net.model.base.CommonSubscriber;
import com.net.model.base.DBSubscriber;
import com.net.model.base.Resource;
import com.net.model.bean.BaseResponse;
import com.net.model.exception.ApiException;
import com.net.model.exception.ExceptionEngine;
import com.net.model.exception.ServerException;
import com.net.model.https.RequetRetrofit;
import com.net.model.livedatas.LiveDataBus;
import com.net.model.utils.Constant;

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Completable;
import io.reactivex.CompletableObserver;
import io.reactivex.Flowable;
import io.reactivex.FlowableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;

/**
 * 版权：周和权 版权所有
 *
 * @author zhouhequan
 * 版本：1.0
 * 创建日期：2021/11/12 or 22:24
 * 描述：---
 */
public abstract class BaseModel {
    protected CompositeDisposable mDisposable;

    /**
     * 请求网络
     *
     * @param flowable
     * @param <T>
     * @return
     */
    public <T> BaseHttpSubscriber<T> request(Flowable<BaseResponse<T>> flowable) {
        BaseHttpSubscriber<T> baseHttpSubscriber = new BaseHttpSubscriber<>(); //RxJava Subscriber回调
        addSubscribe(flowable.subscribeOn(Schedulers.io()) //解决背压
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(baseHttpSubscriber));
        return baseHttpSubscriber;
    }

    public <T> MutableLiveData<Resource<T>> requestNew(Flowable<BaseResponse<T>> flowable) {
        MutableLiveData<Resource<T>> liveData = new MutableLiveData();
        Disposable disposable = flowable.compose(rxSchedulerHelper())
                .compose(handleHttpResult())
                .subscribeWith(new CommonSubscriber<T>(liveData));
        addSubscribe(disposable);
        return liveData;
    }


    public MutableLiveData<Resource<Integer>> requestDB(Completable completable) {
        MutableLiveData<Resource<Integer>> liveData = new MutableLiveData();
        completable.subscribeOn(Schedulers.io()) //解决背压
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new CompletableObserver() {

                    @Override
                    public void onSubscribe(Disposable d) {
                        addSubscribe(d);
                    }

                    @Override
                    public void onComplete() {
                        DLog.i("数据插入成功");
                        if (liveData != null)
                            liveData.postValue(Resource.responseDB(Constant.CODE_SUCCESS));
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                        DLog.i("数据插入失败：" + e.getMessage());
                        ApiException ex = ExceptionEngine.handleException(e);
                        if (liveData != null)
                            liveData.postValue(Resource.failure(ex.getCode(), ex.getMessage()));
                    }
                });
        return liveData;
    }

    public <T> MutableLiveData<Resource<T>> requestDB(Flowable<T> flowable) {
        MutableLiveData<Resource<T>> liveData = new MutableLiveData();
        addSubscribe(flowable.subscribeOn(Schedulers.io()) //解决背压
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new DBSubscriber<T>(liveData)));
        return liveData;
    }

    public <T> T getApiService(final Class<T> service) {
        return RequetRetrofit.getInstance().getRetrofit(service);
    }

    private static <T> FlowableTransformer<BaseResponse<T>, T> handleHttpResult() {
       return new FlowableTransformer<BaseResponse<T>, T>() {
            @NonNull
            @Override
            public Publisher<T> apply(@NonNull Flowable<BaseResponse<T>> upstream) {
                return (Publisher<T>) upstream.flatMap(new Function<BaseResponse<T>, Publisher<?>>() {
                    @Override
                    public Publisher<?> apply(@NonNull BaseResponse<T> baseResponse) throws Exception {

                        if ((baseResponse.getCode().intValue() == Constant.CODE_SUCCESS.intValue())) {
                            if (baseResponse.getData() == null) {
                                ServerException serverException = new ServerException(Constant.EMPTY_DATA_ERROR, "empty");
                                return Flowable.error(serverException);
                            }
                            return createData(baseResponse.getData());
                        } else {
                            //Token失效
                            if (baseResponse.getCode().intValue() == Constant.CODE_AUTH_FAIL) {
                                LiveDataBus.get("invalid-token", Integer.class).post(Constant.CODE_AUTH_FAIL);
                            }
                            ServerException serverException = new ServerException(baseResponse.getCode(), baseResponse.getMessage());
                            return Flowable.error(serverException);
                        }
                    }
                });
            }
        };
    }

    private static <T> Flowable<T> createData(final T t) {
        return Flowable.create(emitter -> {
            try {
                emitter.onNext(t);
                emitter.onComplete();
            } catch (Exception e) {
                emitter.onError(e);
            }
        }, BackpressureStrategy.BUFFER);
    }

    private <T> FlowableTransformer<T, T> rxSchedulerHelper() {    //compose简化线程
        return flowable -> flowable
                .subscribeOn(Schedulers.io())//1. 指定被观察者 生产事件的线程
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()); // 2. 指定观察者 接收 & 响应事件的线程

    }

    /**
     * description: 添加订阅
     *
     * @author: zhouhequan
     * @date: 2021/10/25 11:33
     * @Param disposable:
     * @return: void
     */

    public final void addSubscribe(Disposable disposable) {
        if (mDisposable == null) {
            mDisposable = new CompositeDisposable();
        }
        mDisposable.add(disposable);
    }

    /**
     * description: 解除订阅
     *
     * @author: zhouhequan
     * @date: 2021/10/25 11:33
     * @return: void
     */

    public void unSubscribe() {
        if (mDisposable != null) {
            mDisposable.dispose();
        }
    }

}
